﻿#region Includes
using System;
using System.Diagnostics;
using System.Collections.Generic;
using OpenTK.Graphics;
#endregion

namespace GingerGL.Graphics
{
    //------------------------------------------------------------//
    /// <summary>
    /// Unmanaged Resource Class
    /// </summary>
    public abstract class Unmanaged
    {
        //--------------------------------------------------------//
        #region Properties
        /// <summary>
        /// List of all unmanaged resources
        /// </summary>
        static public List<Unmanaged> Instance = new List<Unmanaged>();
        /// <summary>
        /// Gets list of unmanaged OpenGL ID's
        /// </summary>
        public int[] ResourceIDs { get; protected set; }
        /// <summary>
        /// Get current OpenGL Context
        /// </summary>
        public IGraphicsContext Context { get; protected set; }
        /// <summary>
        /// Gets TRUE it unoaded
        /// </summary>
        public bool Unloaded { get; private set; }
        #endregion
        //--------------------------------------------------------//
        #region Constructor
        /// <summary>
        /// Initalizes a new instance of object
        /// </summary>
        public Unmanaged()
        {
            this.Context = GraphicsContext.CurrentContext;
            if (this.Context == null)
                throw new InvalidOperationException(String.Format("No OpenGL context available in thread {0}.", System.Threading.Thread.CurrentThread.ManagedThreadId));
            Unmanaged.Instance.Add(this);
        }
        #endregion
        //--------------------------------------------------------//
        #region Methods
        /// <summary>
        /// Required Event when Resource is ready to be deleted
        /// </summary>
        protected abstract void OnDeleteResource();
        /// <summary>
        /// 
        /// </summary>
        /// <param name="manualDisposing"></param>
        private void Unload(bool manualDisposing)
        {
            try
            {
                if (this.ResourceIDs== null || this.ResourceIDs.Length == 0)
                {
                    this.Unloaded = true;
                    return;
                }
                if (this.Unloaded == false)
                {
                    var current_context = GraphicsContext.CurrentContext;

                    if (current_context == this.Context)
                    {
                        OnDeleteResource();
                        this.Unloaded = true;

                        if (manualDisposing == false)
                        {
                            Debug.WriteLine(String.Format("[Message] Disposing resource {0} from finalizer.", this));
                        }
                    }
                    else
                    {
                        Debug.Print("[Warning] Attempted to free {0} through GraphicsContext: {1}.", this,
                                    current_context == null ? "null" : current_context.ToString());
                        // Don't mark the resource as Unloaded_ to give the user a (misguided?) chance to dispose it using the correct context.
                    }
                }
            }
            finally
            {
                Unmanaged.Instance.Remove(this);
            }
        }
        /// <summary>
        /// Unload Resources
        /// </summary>
        protected virtual void Unload()
        {
            Unload(true);
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// Old School Desconstructor
        /// </summary>
        ~Unmanaged() { Unload(false); }
        /// <summary>
        /// Unmanaged To String
        /// </summary>
        public override string ToString()
        {
            return String.Format("{0} (resourceIDs: {1}, context: {2}", GetType(), this.ResourceIDs, this.Context);
        }
        /// <summary>
        /// Clears Everything!
        /// </summary>
        static internal void DiscardRemainingResources()
        {
            while (Unmanaged.Instance.Count > 0)                //clear all
                Unmanaged.Instance[0].Unload();                 //all unload
        }
        #endregion
        //--------------------------------------------------------//
    }
    //------------------------------------------------------------//
}
